package com.tyfspring.context.support;

import com.tyfspring.beans.aware.ApplicationContextAwareProcessor;
import com.tyfspring.beans.config.BeanFactoryPostProcessor;
import com.tyfspring.beans.config.BeanPostProcessor;
import com.tyfspring.beans.exception.BeansException;
import com.tyfspring.beans.factory.ConfigurableListableBeanFactory;
import com.tyfspring.context.ApplicationEvent;
import com.tyfspring.context.ApplicationListener;
import com.tyfspring.context.ConfigurableApplicationContext;
import com.tyfspring.context.event.ApplicationEventMuticaster;
import com.tyfspring.context.event.ContextClosedEvent;
import com.tyfspring.context.event.ContextRefreshedEvent;
import com.tyfspring.context.event.SimpleApplicationEventMuticaster;
import com.tyfspring.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 * @Description 应用上下文抽象类实现
 * 继承DefaultResourceLoader是为了处理spring.xml配置资源的加载
 * @Author shallow
 * @Date 2023/4/5 4:21
 */

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMuticaster applicationEventMuticaster;

    @Override
    public void refresh() throws BeansException {
        //1.创建BeanFactory，并加载BeanDefinition
        refreshBeanFactory();

        //2.获取BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        //2.5
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        //3.Bean实例化前，执行BeanFactory后处理器

        invokeBeanFactoryPostProcessors(beanFactory);

        //4.bean后处理器要提前其他bean对象实例化之前执行注册操作
        registerBeanPostProcessors(beanFactory);

        //5.提前实例化单例bean对象
        beanFactory.preInstantiateSingletons();

        //6.初始化事件发布者
        initApplicationEventMuticaster();

        //7.注册事件监听器
        registerListeners();

        //9.发布容器刷新完成事件
        finishRefresh();
    }

    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    private void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMuticaster.addApplicationListener(listener);
        }
    }

    private void initApplicationEventMuticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        applicationEventMuticaster = new SimpleApplicationEventMuticaster(beanFactory);

        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,applicationEventMuticaster);
    }

    protected abstract void refreshBeanFactory() throws BeansException;

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    /**
     * 注入beanFactory后处理器
     * @param beanFactory
     */
    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory){
        //按类获取所有的BeanFactory后处理器
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory){
        //添加bean后处理器
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
        publishEvent(new ContextClosedEvent(this));
        getBeanFactory().destroySingletons();
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name,args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name,requiredType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMuticaster.muticastEvent(event);
    }
}
